/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.gui.activity;

import java.io.File;

import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import de.fuberlin.kosmik.R;
import de.fuberlin.kosmik.data.DataBaseConnector;
import de.fuberlin.kosmik.data.osmt.OsmtElementRecord;
import de.fuberlin.kosmik.files.MediaController;
import de.fuberlin.kosmik.gui.view.MapFrame;
import de.fuberlin.kosmik.log.Constants;
import de.fuberlin.kosmik.trackrecorder.TrackRecorderService;

/**
 * @author Johannes
 */
public class ViewActivity extends TrackActivity implements OnClickListener {

	private static final int INTENT_POI_PICKER = 1;
	private static final int INTENT_WAY_PICKER = 2;
	private static final int INTENT_AREA_PICKER = 3;

	private static final String MEDIA_FILE = "media_file";
	private static final String IS_WAY_TRACKING = "way_tracking";
	private static final String IS_AREA_TRACKING = "area_tracking";

	private TrackRecorderService trackService;
	private MapFrame mapFrame;

	private Button btnPOI;
	private Button btnWay;
	private Button btnArea;
	private Button btnMedia;
	private ImageButton btnPauseResume;
	private ImageButton btnShowList;
	/**
	 * Id of the current track.
	 */
	long trackId;

	// we must memorize state of toggle buttons
	private boolean isWayTracking = false;
	private boolean isAreaTracking = false;
	/**
	 * State of the recorder (recording / not recording).
	 */
	boolean isTracking = true;
	private MediaController mediaController;
	/**
	 * Reference to the database.
	 */
	DataBaseConnector dataBase;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		dataBase = getDataBase();
		Log.d(Constants.TAG, "ViewActivity onCreate trackService:" + getTrackService());

		if (!TrackRecorderService.isServiceRunning()) {
			isTracking = false;
			showServiceNotRunningDialog();
			finish();
			return;
		}

		setContentView(R.layout.view);

		findViewsAndSetListener();

		trackId = getTrackService().getCurrentTrackId();
		mapFrame.setIsRecording(true);

		mapFrame.setTrackId(trackId);

		registerForContextMenu(btnMedia);

		mediaController = new MediaController(this, trackId);

		if (savedInstanceState != null) {
			if (savedInstanceState.containsKey(MEDIA_FILE)) {
				mediaController.setCurrentFile(savedInstanceState.getString(MEDIA_FILE));
			}
			// rebuild the state of the way and area buttons
			isWayTracking = savedInstanceState.getBoolean(IS_WAY_TRACKING, false);
			updateTextOfWayButton();
			isAreaTracking = savedInstanceState.getBoolean(IS_AREA_TRACKING, false);
			updateTextOfAreaButton();
		}
	}

	private void showServiceNotRunningDialog() {
		Toast toast = Toast.makeText(this,
				"Unable to find the location service, please restart kOSMik!",
				Toast.LENGTH_LONG);
		toast.show();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		File currentFile = mediaController.getCurrentFile();
		if (null != currentFile) {
			outState.putString(MEDIA_FILE, currentFile.toString());
		}
		outState.putBoolean(IS_WAY_TRACKING, isWayTracking);
		outState.putBoolean(IS_AREA_TRACKING, isAreaTracking);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		Log.d(Constants.TAG,
				"VA onDestroy, ServiceIsRunning:" + TrackRecorderService.isServiceRunning());
		if (TrackRecorderService.isServiceRunning()) {
			getTrackService().unregisterLocationUpdates();
			if (!isTracking) {
				// kills service if we are not still tracking and service is
				// available
				getTrackService().stopTrack();
				TrackRecorderService.stopService(this);
			}

		}
	}

	@Override
	public void onStart() {
		super.onStart();
		if (isTracking) {
			trackService = getTrackService();
			trackService.registerLocationUpdates(mapFrame);
			mapFrame.registerService(trackService);
			// mapFrame.initMap();
		}

	}

	@Override
	public void onStop() {
		super.onStop();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// set optionsmenu defined in res.menu.start
		getMenuInflater().inflate(R.menu.view, menu);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.opt_editSettings:
			final Intent intent = new Intent(this, SettingsActivity.class);
			startActivity(intent);
			break;
		case R.id.opt_stopTrack:
			showStopTrackDialog();
			break;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	/**
	 * Find views and set activity as OnCLickListener.
	 */
	private void findViewsAndSetListener() {
		// OsMapView
		mapFrame = (MapFrame) findViewById(R.id.map_frame);
		// Buttons
		btnPOI = (Button) findViewById(R.id.view_btnAddPOI);
		Log.d(Constants.TAG, "before mapFrame was found");
		btnPOI.setOnClickListener(this);
		btnWay = (Button) findViewById(R.id.view_btnWay);
		btnWay.setOnClickListener(this);
		btnArea = (Button) findViewById(R.id.view_btnArea);
		btnArea.setOnClickListener(this);
		btnMedia = (Button) findViewById(R.id.view_btnMedia);
		btnMedia.setOnClickListener(this);
		btnPauseResume = (ImageButton) findViewById(R.id.action_bar_pause_button);
		btnPauseResume.setOnClickListener(this);
		btnShowList = (ImageButton) findViewById(R.id.action_bar_show_list_button);
		btnShowList.setOnClickListener(this);

		TextView title = (TextView) findViewById(R.id.action_bar_title);
		title.setText(R.string.view__title);
	}

	@Override
	public void onClick(View view) {
		int viewId = view.getId();

		// if the poi button is pressed, TagPickerActivity is starting so the
		// user can pick the right poi tag.
		if (viewId == btnPOI.getId()) {
			letUserPickAPoi();
		}
		// if the way button is pressed, TagPickerActivity is starting so the
		// user can pick the right way tag or the current way is stopped, if
		// isWayTracking is true.
		else if (viewId == btnWay.getId()) {
			if (!isWayTracking) {
				letUserStartWayTracking();
			} else {
				stopTrackingOfCurrentWay();
			}

		}
		// if the area button is pressed, TagPickerActivity is starting so the
		// user can pick the right area tag or the current area is stopped, if
		// isAreaTracking is true.
		else if (viewId == btnArea.getId()) {
			if (!isAreaTracking) {
				letUserStartAreaTracking();
			} else {
				stopTrackingOfCurrentArea();
			}
		}
		// pauses or resumes the tracking and updates button.
		else if (viewId == btnPauseResume.getId()) {
			if (isTracking) { // pause Track and change icon
				pauseTracking();
			} else { // resume Track and change icon
				resumeTracking();
			}
		}
		// Opens contextMenu of the media button
		else if (viewId == btnMedia.getId()) {
			btnMedia.performLongClick();
		}
		// Starts TrackInfoActivity to show all items that yet has been tracked.
		else if (viewId == btnShowList.getId()) {
			Intent intent = new Intent(ViewActivity.this, TrackInfoActivity.class);
			intent.putExtra(TrackInfoActivity.TRACK_ID, getTrackService().getCurrentTrackId());
			intent.putExtra(TrackInfoActivity.IS_SAVED_TRACK, false);
			startActivity(intent);
		}
	}

	private void pauseTracking() {
		getTrackService().pauseTrack();
		btnPauseResume.setImageResource(R.drawable.ic_action_bar_resume);
		isTracking = false;
		btnPOI.setEnabled(false);
		btnArea.setEnabled(false);
		btnMedia.setEnabled(false);
		btnWay.setEnabled(false);
	}

	private void resumeTracking() {
		getTrackService().resumeTrack();
		btnPauseResume.setImageResource(R.drawable.ic_action_bar_pause);
		isTracking = true;
		btnPOI.setEnabled(true);
		btnArea.setEnabled(true);
		btnMedia.setEnabled(true);
		btnWay.setEnabled(true);
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
		Log.d(Constants.TAG, "Long pressed");
		switch (view.getId()) {

		case R.id.view_btnMedia:
			getMenuInflater().inflate(R.menu.view_media_context, menu);
			break;
		default:
			break;
		}

		super.onCreateContextMenu(menu, view, menuInfo);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.opt_media_audio:
			startAudioRecording();
			break;
		case R.id.opt_media_picture:
			startPictureRecording();
			break;
		case R.id.opt_media_textnote:
			startNote();
			break;
		case R.id.opt_media_video:
			startVideoRecording();
			break;
		default:
			break;
		}
		return super.onContextItemSelected(item);
	}

	/**
	 * Starts TagPickerActivity with a list of poi tags.
	 */
	void letUserPickAPoi() {
		final Intent tagPickerActivityIntent = new Intent(this, TagPickerActivity.class);
		tagPickerActivityIntent.putExtra("TITLE", getString(R.string.view__poipicker_title));
		// do not uncomment the statement below, cause this will produce in
		// the calling activity the value null for the attribute
		// osmParentStructureNodeName,
		// in this case all root items will inserted in the list by default
		// tagPickerActivityIntent.putExtra( "OSM_PARENT_STRUCTURE_NODE_NAME",
		// "");
		tagPickerActivityIntent.putExtra("OSM_ELEMENT_FILTER", OsmtElementRecord.ELEMENT_NODE);
		// now start the subactivity
		startActivityForResult(tagPickerActivityIntent, INTENT_POI_PICKER);
	}

	/**
	 * Starts TagPickerActivity with a list of way related tags.
	 */
	void letUserStartWayTracking() {

		final Intent tagPickerActivityIntent = new Intent(this, TagPickerActivity.class);
		tagPickerActivityIntent.putExtra("TITLE", getString(R.string.view__waypicker_title));
		tagPickerActivityIntent.putExtra("OSM_ELEMENT_FILTER", OsmtElementRecord.ELEMENT_WAY);
		// now start the subactivity
		startActivityForResult(tagPickerActivityIntent, INTENT_WAY_PICKER);
	}

	/**
	 * Starts TagPickerActivity with a list of area related tags.
	 */
	void letUserStartAreaTracking() {

		final Intent tagPickerActivityIntent = new Intent(this, TagPickerActivity.class);
		tagPickerActivityIntent.putExtra("TITLE", getString(R.string.view__areapicker_title));
		tagPickerActivityIntent.putExtra("OSM_ELEMENT_FILTER", OsmtElementRecord.ELEMENT_AREA);
		// now start the subactivity
		startActivityForResult(tagPickerActivityIntent, INTENT_AREA_PICKER);
	}

	/**
	 * Catches the return result of a called sub-activity.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case INTENT_POI_PICKER:
			if (resultCode == Activity.RESULT_OK) {
				processPoiPickerResult(data);
			}
			break;
		case INTENT_WAY_PICKER:
			if (resultCode == Activity.RESULT_OK) {
				processWayPickerResult(data);
			}
			break;
		case INTENT_AREA_PICKER:
			if (resultCode == Activity.RESULT_OK) {
				processAreaPickerResult(data);
			}
			break;
		case MediaController.INTENT_TAKE_PICTURE:
			mediaController.handleImageResult(resultCode);
			break;
		default:
			break;
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// Handle the back button
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			showStopTrackDialog();
			return true;
		}
		return super.onKeyDown(keyCode, event);

	}

	/**
	 * Process the returned data from a call of the sub-activity
	 * TagPickerActivity, where the user had chosen a POI.
	 * 
	 * @param data The {@link Intent} object, over which the extra data is sent
	 */
	private void processPoiPickerResult(Intent data) {
		Bundle osmTagBundle = data.getExtras();
		if (osmTagBundle != null) {
			// extract the bundles name from extras
			final String osmBundleName = osmTagBundle.getString("BUNDLE_NAME");
			final Bundle osmKeyValueBundle = osmTagBundle.getBundle("KEY_VALUE_BUNDLE");

			// DEBUG:
			Log.d(Constants.TAG, String.format(
					"GUI.VA.processPOIPickerResult: add POI with following %d tags.",
					Integer.valueOf(osmKeyValueBundle.size())));
			for (String key : osmKeyValueBundle.keySet()) {
				Log.d(Constants.TAG, String.format("GUI.VA.processPOIPickerResult: tag %s=%s",
						key, osmKeyValueBundle.getString(key)));
			}

			// and pass the result bundle to trackService
			getTrackService().onPOI(osmKeyValueBundle);
			// inform the user about the acceptance of his selection
			Toast.makeText(this,
					String.format(getString(R.string.view__add_poi_succeed), osmBundleName),
					Toast.LENGTH_LONG).show();

		}

	}

	/**
	 * Process the returned data from a call of the sub-activity
	 * TagPickerActivity, where the user had chosen a way.
	 * <p/>
	 * send the tag bundle received in data to the track service
	 * <p/>
	 * toggles the way button
	 * <p/>
	 * in case of succeed shows an toast message on screen
	 */
	private void processWayPickerResult(Intent data) {
		Bundle osmTagBundle = data.getExtras();
		if (osmTagBundle != null) {

			isWayTracking = true;
			updateTextOfWayButton();

			// extract the bundles name from extras
			final String osmBundleName = osmTagBundle.getString("BUNDLE_NAME");
			final Bundle osmKeyValueBundle = osmTagBundle.getBundle("KEY_VALUE_BUNDLE");

			// DEBUG:
			Log.d(Constants.TAG, String.format(
					"GUI.VA.processWayPickerResult: start way with following %d tags.",
					Integer.valueOf(osmKeyValueBundle.size())));
			for (String key : osmKeyValueBundle.keySet()) {
				Log.d(Constants.TAG, String.format("GUI.VA.processWayPickerResult: tag %s=%s",
						key, osmKeyValueBundle.getString(key)));
			}

			// and pass the result bundle to trackService
			getTrackService().startWay(osmKeyValueBundle);
			// inform the user about the acceptance of his selection
			Toast.makeText(this,
					String.format(getString(R.string.view__start_way_tracking), osmBundleName),
					Toast.LENGTH_LONG).show();

			btnWay.setText(R.string.view__btn_stop_way);

		}
	}

	/**
	 * Process the returned data from a call of the sub-activity
	 * TagPickerActivity, where the user had chosen an area.
	 * <p/>
	 * send the tag bundle received in data to the track service
	 * <p/>
	 * toggles the area button
	 * <p/>
	 * in case of succeed shows an toast message on screen
	 */
	private void processAreaPickerResult(Intent data) {
		Bundle osmTagBundle = data.getExtras();
		if (osmTagBundle != null) {

			isAreaTracking = true;
			updateTextOfAreaButton();

			// extract the bundles name from extras
			final String osmBundleName = osmTagBundle.getString("BUNDLE_NAME");
			final Bundle osmKeyValueBundle = osmTagBundle.getBundle("KEY_VALUE_BUNDLE");

			// DEBUG:
			Log.d(Constants.TAG, String.format(
					"GUI.VA.processAreaPickerResult: start area with following %d tags.",
					Integer.valueOf(osmKeyValueBundle.size())));
			for (String key : osmKeyValueBundle.keySet()) {
				Log.d(Constants.TAG, String.format("GUI.VA.processAreaPickerResult: tag %s=%s",
						key, osmKeyValueBundle.getString(key)));
			}

			// and pass the key value bundle to trackService
			getTrackService().startArea(osmKeyValueBundle);
			// inform the user about the acceptance of his selection
			Toast.makeText(
					this,
					String.format(getString(R.string.view__start_area_tracking), osmBundleName),
					Toast.LENGTH_LONG).show();

		}
	}

	private void updateTextOfWayButton() {
		if (isWayTracking) {
			btnWay.setText(R.string.view__btn_stop_way);
		} else {
			btnWay.setText(R.string.view__btn_start_way);
		}
	}

	private void updateTextOfAreaButton() {
		if (isAreaTracking) {
			btnArea.setText(R.string.view__btn_stop_area);
		} else {
			btnArea.setText(R.string.view__btn_start_area);
		}
	}

	private void stopTrackingOfCurrentWay() {

		getTrackService().stopWay(new Bundle());
		isWayTracking = false;
		updateTextOfWayButton();
	}

	private void stopTrackingOfCurrentArea() {

		getTrackService().closeArea(new Bundle());
		isAreaTracking = false;
		updateTextOfAreaButton();
	}

	/**
	 * Starts a audio recording if we have already a gps fix otherwise informs
	 * user.
	 */
	private void startAudioRecording() {
		if (getTrackService().isTracking()) {
			long pointId = getTrackService().getCurrentPointId();

			Log.d(Constants.TAG, "startAudioRecording trackId:"
					+ getTrackService().getCurrentTrackId() + " pointId:" + pointId);
			Intent audioIntent = new Intent(this, AudioRecordActivity.class);
			audioIntent.putExtra(AudioRecordActivity.INTENT_PARAM_TRACK_ID, getTrackService()
					.getCurrentTrackId());
			audioIntent.putExtra(AudioRecordActivity.INTENT_PARAM_POINT_ID, pointId);
			this.startActivity(audioIntent);
		} else {
			showAlertNoGpsFix();
		}
	}

	/**
	 * Starts note activity if we have already a gps fix otherwise informs user.
	 */
	private void startNote() {
		if (getTrackService().isTracking()) {
			long pointId = getTrackService().getCurrentPointId();

			Log.d(Constants.TAG, "startNote trackId:" + getTrackService().getCurrentTrackId()
					+ " pointId:" + pointId);
			Intent intent = new Intent(this, NoteActivity.class);
			intent.putExtra(NoteActivity.INTENT_PARAM_POINT_ID, pointId);
			this.startActivity(intent);
		} else {
			showAlertNoGpsFix();
		}
	}

	private void startVideoRecording() {
		if (getTrackService().isTracking()) {
			long pointId = getTrackService().getCurrentPointId();

			Log.d(Constants.TAG, "startVideoRecording trackId:"
					+ getTrackService().getCurrentTrackId() + " pointId:" + pointId);
			Intent intent = new Intent(this, VideoRecordActivity.class);
			intent.putExtra(VideoRecordActivity.INTENT_PARAM_TRACK_ID, getTrackService()
					.getCurrentTrackId());
			intent.putExtra(VideoRecordActivity.INTENT_PARAM_POINT_ID, pointId);
			this.startActivity(intent);
		} else {
			showAlertNoGpsFix();
		}
	}

	private void startPictureRecording() {
		if (getTrackService().isTracking()) {
			mediaController.recordImage(getTrackService().getCurrentPointId());
		} else {
			showAlertNoGpsFix();
		}
	}

	private void showAlertNoGpsFix() {
		Toast toast = Toast.makeText(this, "no gps fix => no recording", Toast.LENGTH_LONG);
		toast.show();
	}

	private void showStopTrackDialog() {

		final Dialog dialog = new Dialog(this);
		dialog.setContentView(R.layout.stop_track_dialog);
		dialog.setTitle(R.string.view__stop_track_dialog_title);
		// find all views of the dialog
		Button btnSave = (Button) dialog.findViewById(R.id.stop_track_dialog_save);
		Button btnNotSave = (Button) dialog.findViewById(R.id.stop_track_dialog_not_save);
		Button btnNo = (Button) dialog.findViewById(R.id.stop_track_dialog_no);
		final EditText editTrackName = (EditText) dialog
				.findViewById(R.id.stop_track_dialog_trackname);
		editTrackName.setHint(trackService.getCurrentTrackName());
		btnSave.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// if user changed track name, saves change in db
				String trackName = editTrackName.getText().toString();
				if (!trackName.equals("")) {
					dataBase.setTrackName(trackId, trackName);
				}
				// necessary for killing the service
				isTracking = false;
				getTrackService().stopTrack();
				dialog.dismiss();
				ViewActivity.this.finish();
			}
		});
		btnNotSave.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// necessary for killing the service
				isTracking = false;
				getTrackService().stopTrack();
				dataBase.removeTrack(trackId);
				dialog.dismiss();
				ViewActivity.this.finish();
			}
		});
		btnNo.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				dialog.dismiss();
			}
		});
		dialog.show();
	}
}
